home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Eudora 1.3.1 / source / compact.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  29.5 KB  |  1,136 lines  |  [TEXT/MPS ]

  1. #define FILE_NUM 8
  2. /* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
  3. #pragma load EUDORA_LOAD
  4. #pragma segment Outgoing
  5. /************************************************************************
  6.  * private functions
  7.  ************************************************************************/
  8.     void CompSwitchFields(MessType **messH, Boolean forward);
  9.     void CompAttach(MyWindowPtr win);
  10.     void CompFixDisplay(MyWindowPtr win,short oldBottom,short newBottom,Boolean body);
  11.     void ScrollWinRect(MyWindowPtr win, Rect *scroll, Rect *good, short offset);
  12.     void DrawIconBar(MyWindowPtr win);
  13.     void PlotFlag(Rect *r,unsigned long flags,unsigned long which);
  14.     void ScrollSlice(MyWindowPtr win, short top, short bottom, short offset);
  15.     void CompAdjBar(MyWindowPtr win);
  16.     uLong QueueDate2Secs(UPtr timeStr,UPtr dateStr);
  17.     Rect *CompIconRect(Rect *r,MessHandle messH,short index);
  18. #define I_WIDTH 32
  19. #pragma segment Balloon
  20. /************************************************************************
  21.  * CompHelp - provide help for composition windows
  22.  ************************************************************************/
  23. void CompHelp(MyWindowPtr win,Point mouse)
  24. {
  25.     MessHandle messH = (MessHandle)((WindowPeek)win)->refCon;
  26.     int tx;
  27.     TEHandle teh;
  28.     Rect vr;
  29.     short hnum=1;
  30.     ControlHandle sendButton=(*messH)->sendButton;
  31.     short i;
  32.     
  33.     for (tx=0;tx<HEAD_LIMIT;hnum++,tx++)
  34.     {
  35.         teh = (*messH)->txes[tx];
  36.         vr = (*teh)->viewRect;
  37.         if (PtInRect(mouse,&vr))
  38.         {
  39.             HelpRect(&vr,COMP_HELP_STRN+hnum,0);
  40.             return;
  41.         }
  42.     }
  43.     
  44.     if (GetPriorityRect(win,&vr))
  45.     {
  46.         if (PtInRect(mouse,&vr))
  47.         {
  48.             PriorMenuHelp(win,&vr);
  49.             return;
  50.         }
  51.         
  52.         vr = (*sendButton)->contrlRect;
  53.         if (PtInRect(mouse,&vr))
  54.         {
  55.             if (PrefIsSet(PREF_AUTO_SEND)) hnum++;
  56.             HelpRect(&vr,COMP_HELP_STRN+hnum,100);
  57.             return;
  58.         }
  59.         hnum += 2;
  60.         
  61.         if (win->topMargin)
  62.         {
  63.             for (i=0;i<ICON_BAR_NUM;i++,hnum+=2)
  64.             {
  65.                 if (PtInRect(mouse,CompIconRect(&vr,messH,i)))
  66.                 {
  67.                     switch(i)
  68.                     {
  69.                         case 0:
  70.                             if (SumOf(messH)->flags&FLAG_SIG) hnum++;
  71.                             break;
  72.                         case 1:
  73.                             if (SumOf(messH)->flags&FLAG_WRAP_OUT) hnum++;
  74.                             break;
  75.                         case 2:
  76.                             if (SumOf(messH)->flags&FLAG_TABS) hnum++;
  77.                             break;
  78.                         case 3:
  79.                             if (SumOf(messH)->flags&FLAG_KEEP_COPY) hnum++;
  80.                             break;
  81.                         case 4:
  82.                             if (SumOf(messH)->flags&FLAG_BX_TEXT) hnum++;
  83.                             break;
  84.                     }
  85.                     HelpRect(&vr,COMP_HELP_STRN+hnum,100);
  86.                     return;
  87.                 }
  88.             }
  89.         }
  90.     }
  91. }
  92.  
  93. #pragma segment Main
  94. /**********************************************************************
  95.  * CompClose - close a composition window.    save the contents, iff
  96.  * they're dirty.
  97.  **********************************************************************/
  98. Boolean CompClose(MyWindowPtr win)
  99. {
  100.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  101.     int which;
  102.     
  103.     if (win->isDirty && !NoSaves)
  104.     {
  105.         which = WannaSave(win);
  106.         if (which==WANNA_SAVE_CANCEL || which==CANCEL_ITEM) return(False);
  107.         else if (which == WANNA_SAVE_SAVE && !SaveComp(win)) return(False);
  108.     }
  109.     
  110.     for (which=0;which<HEAD_LIMIT;which++)
  111.     {
  112.         if ((*messH)->txes[which])
  113.         {
  114.             TEDispose((*messH)->txes[which]);
  115.             (*messH)->txes[which] = nil;
  116.         }
  117.     }
  118.     LL_Remove(MessList,messH,(MessType **));
  119.     (*(*messH)->tocH)->sums[(*messH)->sumNum].messH = nil;
  120.     win->txe = nil;
  121.     
  122.     if (((*(*messH)->tocH)->sums[(*messH)->sumNum].flags & FLAG_NBK)!=0)
  123.         DeleteSum((*messH)->tocH,(*messH)->sumNum);
  124.     DisposHandle(messH);
  125.     return(True);
  126. }
  127. #pragma segment Outgoing
  128.  
  129.  
  130. /************************************************************************
  131.  * CompZoomSize - figure the zoomed size of a comp window
  132.  ************************************************************************/
  133. void CompZoomSize(MyWindowPtr win,Rect *zoom)
  134. {
  135. #pragma unused(win)
  136.     short hi,wi;
  137.     
  138.     if (!(wi=GetRLong(PREF_STRN+PREF_MWIDTH))) wi=GetRLong(DEF_MWIDTH);
  139.     wi *= win->hPitch; wi += GROW_SIZE; wi+=2*TE_HMARGIN;
  140.     
  141.     zoom->right = zoom->left + MIN(zoom->right-zoom->left,wi);
  142.     
  143.     if (hi=GetRLong(PREF_STRN+PREF_MHEIGHT))
  144.     {
  145.         hi *= win->vPitch;
  146.         zoom->bottom = MIN(zoom->bottom,zoom->top+hi);
  147.     }
  148. }
  149.     
  150. /**********************************************************************
  151.  * CompScroll - scroll a composition window (not a pretty sight...)
  152.  **********************************************************************/
  153. Boolean CompScroll(MyWindowPtr win,int h,int v)
  154. {
  155. #pragma unused(h)
  156.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  157.     int tx;
  158.     short offset = win->vPitch * v;
  159.     
  160.     /*
  161.      * move the fields
  162.      */
  163.     for (tx=0; tx<HEAD_LIMIT; tx++)
  164.         OffsetTE(win,(*messH)->txes[tx],offset);
  165.     
  166.     /*
  167.      * make sure sanity prevails
  168.      */
  169.     CompAdjBar(win);
  170.     
  171.     return(True);
  172. }
  173.  
  174. /**********************************************************************
  175.  * CompDidResize - take care of a resized composition window
  176.  **********************************************************************/
  177. void CompDidResize(MyWindowPtr win, Rect *oldContR)
  178. {
  179. #pragma unused(oldContR)
  180.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  181.     short v;
  182.     short h;
  183.     TEHandle teh;
  184.     Str255 scratch;
  185.     short which;
  186.     short cTop = win->contR.top;
  187.     short cBot = win->contR.bottom;
  188.     ControlHandle sendButton;
  189.     
  190.     /*
  191.      * the headers
  192.      */
  193.     SetPort(win);
  194.     TextFont(FontID);
  195.     TextSize(FontSize);
  196.     v = win->contR.top - (GetCtlValue(win->vBar) * (short)win->vPitch);
  197.     h = StringWidth(GetRString(scratch,HEADER_LABEL_STRN+ATTACH_HEAD));
  198.     h += FontWidth;
  199.     for (which=TO_HEAD; which < HEAD_LIMIT; which++)
  200.     {
  201.         teh = (*messH)->txes[which-1];
  202.         (*teh)->viewRect.top = MAX(cTop,v);
  203.         (*teh)->viewRect.left = h;
  204.         (*teh)->viewRect.right = win->contR.right;
  205.         (*teh)->destRect = (*teh)->viewRect;
  206.         (*teh)->destRect.top = v;
  207.         INSET_RECT(&(*teh)->destRect,2,0);
  208.         TECalText(teh);
  209.         v += win->vPitch*CountTeLines(teh);
  210.         (*teh)->destRect.bottom = v;
  211.         (*teh)->viewRect.bottom = MIN(v,cBot);
  212.     }
  213.     
  214.     if ((*(*messH)->txes[HEAD_LIMIT-1])->viewRect.bottom < cBot)
  215.         (*(*messH)->txes[HEAD_LIMIT-1])->viewRect.bottom--;
  216.         
  217.     /*
  218.      * the body
  219.      */
  220.     teh = (*messH)->txes[HEAD_LIMIT-1];
  221.     v += win->vPitch;
  222.     (*teh)->viewRect.top = MAX(cTop,v);
  223.     (*teh)->viewRect.bottom = win->contR.bottom;
  224.     (*teh)->viewRect.left = win->contR.left;
  225.     (*teh)->viewRect.right = win->contR.right;
  226.     (*teh)->destRect = (*teh)->viewRect;
  227.     (*teh)->destRect.top = v;
  228.     INSET_RECT(&(*teh)->destRect,2,0);
  229.     TECalText(teh);
  230.     v += win->vPitch*CountTeLines(teh);
  231.     (*teh)->destRect.bottom = MAX(v,win->contR.bottom);
  232.     
  233.     /*
  234.      * and the scroll bar
  235.      */
  236.     MyWindowMaxes(win,0,CountCompLines(messH)+1
  237.         +(win->contR.bottom-win->contR.top)/win->vPitch/2); /* .5 window slop */
  238.     CompAdjBar(win);
  239.     
  240.     /*
  241.      * the send button
  242.      */
  243.     if (sendButton = (*messH)->sendButton)
  244.     {
  245.         Rect r = (*sendButton)->contrlRect;
  246.         OFFSET_RECT(&(*sendButton)->contrlRect,
  247.             ((GrafPtr)win)->portRect.right-(r.right-r.left)/4-r.right,
  248.             (win->topMargin-3-r.bottom+r.top)/2-r.top);
  249.     }
  250.         
  251.     if (win->txe && win->isActive) TEActivate(win->txe);
  252.     InvalRect(&((GrafPtr)win)->portRect);     /* sorry... */
  253. }
  254.  
  255. /**********************************************************************
  256.  * CompClick - handle a click in a comp window.
  257.  **********************************************************************/
  258. void CompClick(MyWindowPtr win, EventRecord *event)
  259. {
  260.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  261.     Point pt;
  262.     int tx;
  263.     TEHandle teh;
  264.     Rect vr;
  265.     short i;
  266.     Boolean in;
  267.     Rect pr;
  268.     
  269.     SetPort(win);
  270.     pt = event->where;
  271.     GlobalToLocal(&pt);
  272.     
  273.     if (GetPriorityRect(win,&pr) && PtInRect(pt,&pr))
  274.         PriorityMenu(win);
  275.     else if (PtInRect(pt,&win->contR))
  276.     {
  277.         for (tx=0;tx<HEAD_LIMIT;tx++)
  278.         {
  279.             teh = (*messH)->txes[tx];
  280.             vr = (*teh)->viewRect;
  281.             if (PtInRect(pt,&vr))
  282.             {
  283.                 CompTxeTo(win,teh);
  284.                 /*(*teh)->clikStuff = 255;*/
  285.                 TEClick(pt, (event->modifiers&shiftKey)!=0, teh);
  286.                 if ((*teh)->selStart==(*teh)->selEnd)
  287.                 {
  288.                     TEDeactivate(teh);
  289.                     (*teh)->clikStuff = 255;
  290.                     TESetSelect((*teh)->selStart,(*teh)->selEnd,teh);
  291.                     TEActivate(teh);
  292.                 }
  293.                 if (tx==ATTACH_HEAD-1)
  294.                     AttachSelect(win->txe);
  295.                 win->hasSelection = (*teh)->selEnd != (*teh)->selStart;
  296.                 break;
  297.             }
  298.         }
  299.         EnableMenus(FrontWindow());
  300.     }
  301.     else if (SumOf(messH)->state!=SENT)
  302.     {
  303.         for (i=0;i<ICON_BAR_NUM;i++)
  304.         {
  305.             if (PtInRect(pt,CompIconRect(&vr,messH,i)))
  306.             {
  307.                 in = False;
  308.                 do
  309.                 {
  310.                     GetMouse(&pt);
  311.                     if (in!=PtInRect(pt,&vr))
  312.                     {
  313.                         in = !in;
  314.                         InvertRect(&vr);
  315.                     }
  316.                 }
  317.                 while (StillDown());
  318.                 if (in)
  319.                 {
  320.                     long flags = SumOf(messH)->flags;
  321.                     InvertRect(&vr);
  322.                     vr.right = (vr.right+vr.left)/2;
  323.                     InvalRect(&vr);
  324.                     switch(i)
  325.                     {
  326.                         case 0:
  327.                             if (flags&FLAG_SIG) flags &= ~FLAG_SIG;
  328.                             else flags|=FLAG_SIG;
  329.                             break;
  330.                         case 1:
  331.                             if (flags&FLAG_WRAP_OUT) flags &= ~FLAG_WRAP_OUT;
  332.                             else flags|=FLAG_WRAP_OUT;
  333.                             break;
  334.                         case 2:
  335.                             if (flags&FLAG_TABS) flags &= ~FLAG_TABS;
  336.                             else flags|=FLAG_TABS;
  337.                             break;
  338.                         case 3:
  339.                             if (flags&FLAG_KEEP_COPY) flags &= ~FLAG_KEEP_COPY;
  340.                             else flags|=FLAG_KEEP_COPY;
  341.                             break;
  342.                         case 4:
  343.                             if (flags&FLAG_BX_TEXT) flags &= ~FLAG_BX_TEXT;
  344.                             else flags|=FLAG_BX_TEXT;
  345.                             break;
  346.                     }
  347.                     SumOf(messH)->flags = flags;
  348.                 }
  349.                 break;
  350.             }
  351.         }
  352.     }
  353. }
  354.  
  355. /************************************************************************
  356.  * CompTxeTo - set the txe of a comp window
  357.  ************************************************************************/
  358. void CompTxeTo(MyWindowPtr win,TEHandle teh)
  359. {
  360.     if (teh != win->txe)
  361.     {
  362.         MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  363.         if (win->txe)
  364.             TEDeactivate(win->txe);
  365.         TEActivate(teh);
  366.         win->txe = teh;
  367.         win->ro = (*messH)->txRo[FindCompTx(messH,teh)];
  368.     }
  369. }
  370.  
  371. /**********************************************************************
  372.  * CompMenu - handle menu choice for composition window
  373.  **********************************************************************/
  374. Boolean CompMenu(MyWindowPtr win, int menu, int item, short modifiers)
  375. {
  376. #pragma unused(modifiers)
  377.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  378.     TOCType **tocH = (*messH)->tocH;
  379.     int sumNum = (*messH)->sumNum;
  380.     Str63 which,boxName;
  381.     long dirId;
  382.     uLong when;
  383.     short function,state;
  384.     Boolean now = False;
  385.     
  386.     if (menu==MESSAGE_MENU && item==MESSAGE_QUEUE_ITEM && modifiers&optionKey)
  387.       item = MESSAGE_MOD_Q_ITEM;
  388.     switch (menu)
  389.     {
  390.         case FILE_MENU:
  391.             switch (item)
  392.             {
  393.                 case FILE_SAVE_ITEM:
  394.                     (void) SaveComp(win);
  395.                     return(True);
  396.                 case FILE_SAVE_AS_ITEM:
  397.                     SaveMessageAs(messH);
  398.                     return(True);
  399.                 case FILE_PRINT_ITEM:
  400.                 case FILE_PRINT_SELECT_ITEM:
  401.                     PrintOneMessage((*messH)->win,item==FILE_PRINT_SELECT_ITEM);
  402.                     return(True);
  403.                     break;
  404.             }
  405.             break;
  406.         case EDIT_MENU:
  407.             if (item==EDIT_WRAP_ITEM && modifiers&optionKey) item++;
  408.             return(TESomething(win,item,0,modifiers));
  409.             break;
  410.             
  411.         case MESSAGE_MENU:
  412.             switch (item)
  413.             {
  414.                 case MESSAGE_DELETE_ITEM:
  415.                     DeleteMessage(tocH,sumNum);
  416.                     if ((*tocH)->win)
  417.                         BoxSelectAfter((*tocH)->win,sumNum);
  418.                     return(True);
  419.                 case MESSAGE_QUEUE_ITEM:
  420.                   when = 0;
  421.                     now = PrefIsSet(PREF_AUTO_SEND);
  422.                 queueit:
  423.                     if (SaveComp(win))
  424.                     {
  425.                         if ((*tocH)->sums[sumNum].state == UNSENDABLE)
  426.                             DoNumBigAlert(Stop,CANT_QUEUE);
  427.                         else if (CloseMyWindow(win))
  428.                         {
  429.                             SetState(tocH,sumNum,QUEUED);
  430.                             TimeStamp(tocH,sumNum,when,ZoneSecs());
  431.                             SetSendQueue();
  432.                             if (now && SendQueue) DoSendQueue();
  433.                         }
  434.                     }
  435.                     SetSendQueue();
  436.                     return(True);
  437.                 case MESSAGE_MOD_Q_ITEM:
  438.                   when = (*tocH)->sums[sumNum].seconds;
  439.                     if (ModifyQueue(&state,&when))
  440.                   {
  441.                       if (now = (state==SENT)) state=QUEUED;
  442.                       if (state==QUEUED) goto queueit;
  443.                         if ((*tocH)->sums[sumNum].state==QUEUED)
  444.                           SetState(tocH,sumNum,SENDABLE);
  445.                         SetSendQueue();
  446.                     }
  447.                     return(True);
  448.                 case MESSAGE_FORWARD_ITEM:
  449.                     DoForwardMessage(win,0);
  450.                     return(True);
  451.                     break;
  452.                 case MESSAGE_ATTACH_ITEM:
  453.                     CompAttach(win);
  454.                     return(True);
  455.                     break;
  456.                 case MESSAGE_SALVAGE_ITEM:
  457.                     DoSalvageMessage(win);
  458.                     return(True);
  459.                     break;
  460.             }
  461.             break;
  462.         case FORWARD_TO_HIER_MENU:
  463.             DoForwardMessage(win,item);
  464.             return(True);
  465.             break;
  466.         case SPECIAL_MENU:
  467.             switch(item)
  468.             {
  469.                 case SPECIAL_MAKE_NICK_ITEM:
  470.                     MakeCompNick(win);
  471.                     return(True);
  472.                     break;
  473.             }
  474.             break;
  475.         default:
  476.             if (menu==TRANSFER_MENU)
  477.             {
  478.                 dirId = MyDirId;
  479.                 function = TRANSFER;
  480.             }
  481.             else if (menu<1||menu>=FIND_HIER_MENU) break;
  482.             else
  483.             {
  484.                 dirId = (*BoxMap)[menu % MAX_BOX_LEVELS];
  485.                 function = (menu-1)/MAX_BOX_LEVELS;
  486.             }
  487.             switch (function)
  488.             {
  489.                 case TRANSFER:
  490.                     PCopy(boxName,(*tocH)->name);
  491.                     if (GetTransferParams(menu,item,&dirId,which) &&
  492.                             (dirId!=(*tocH)->dirId || !EqualString(which,boxName,False,True)))
  493.                     {
  494.                         MoveMessage(tocH,sumNum,dirId,which,(modifiers&optionKey)!=0);
  495.                         if (!(modifiers&optionKey) && (*tocH)->win)
  496.                             BoxSelectAfter((*tocH)->win,sumNum);
  497.                     }
  498.                     return(True);
  499.                     break;
  500.                 default:
  501.                     break;
  502.             }
  503.             break;
  504.     }
  505.     return(False);
  506. }
  507.  
  508. /**********************************************************************
  509.  * CompUpdate - draw the contents of a composition window
  510.  **********************************************************************/
  511. void CompUpdate(MyWindowPtr win)
  512. {
  513.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  514.     int which;
  515.     int h,v,w;
  516.     Str63 scratch;
  517.     Rect visR;
  518.     Rect destR;
  519.     TEHandle teh;
  520.     
  521.     PenPat(&qd.gray);
  522.     TextFont(FontID);
  523.     TextSize(FontSize);
  524.     h = StringWidth(GetRString(scratch,HEADER_LABEL_STRN+ATTACH_HEAD))+FontWidth;
  525.     for (which=0;which<HEAD_LIMIT-1;which++)
  526.     {
  527.         teh = (*messH)->txes[which];
  528.         visR = (*teh)->viewRect;
  529.         v = (*teh)->destRect.top + FontAscent;
  530.         w = StringWidth(GetRString(scratch,HEADER_LABEL_STRN+which+1));
  531.         SectRect(&win->contR,&visR,&visR);
  532.         if (visR.top!=visR.bottom && visR.left!=visR.right)
  533.         {
  534.             MoveTo(h-w,v);
  535.             DrawString(scratch);
  536.             TEUpdate(&visR, teh);
  537.         }
  538.     }
  539.     teh = (*messH)->txes[HEAD_LIMIT-1];
  540.     visR = (*teh)->viewRect;
  541.     SectRect(&win->contR,&visR,&visR);
  542.     TEUpdate(&visR, teh);
  543.     destR = (*(*messH)->txes[HEAD_LIMIT-1])->destRect;
  544.     if (destR.top-win->vPitch/2 > win->topMargin)
  545.         {MoveTo(0,destR.top-win->vPitch/2); Line(win->contR.right,0);}
  546.     PenPat(&qd.black);
  547.     if (SumOf(messH)->flags&FLAG_ICON_BAR) DrawIconBar(win);
  548. }
  549.  
  550. /************************************************************************
  551.  * DrawIconBar - draw the icon bar in a window
  552.  * SICN 's are 16x16
  553.  * We center them top & bottom, and another 16 pixels for a checkmark
  554.  ************************************************************************/
  555. void DrawIconBar(MyWindowPtr win)
  556. {
  557.     MessHandle messH = Win2MessH(win);
  558.     unsigned long flags = SumOf(messH)->flags;
  559.     Rect r;
  560.     short i,v;
  561.     Str31 sbName,shdName;
  562.     static short icons[]={FLAG_SIG,FLAG_WRAP_OUT,FLAG_TABS,FLAG_KEEP_COPY,FLAG_BX_TEXT};
  563.     
  564.     TextFont(0);
  565.     TextSize(0);
  566.     
  567.     for (i=0;i<ICON_BAR_NUM;i++)
  568.     {
  569.         CompIconRect(&r,messH,i);
  570.         PlotFlag(&r,flags,icons[i]);
  571.     }
  572.  
  573.     v = win->topMargin-1;
  574.     MoveTo(0,v); LineTo(INFINITY,v);
  575.     MoveTo(0,v-2); LineTo(INFINITY,v-2);
  576.     if (SumOf((MessHandle)win->qWindow.refCon)->state==SENT)
  577.     {
  578.         Rect r;
  579.         PenState oldState;
  580.     
  581.         SetRect(&r,0,0,INFINITY,v-3);
  582.         GetPenState(&oldState);
  583.         PenMode(patBic);
  584.         PenPat(&qd.gray);
  585.         PaintRect(&r);
  586.         SetPenState(&oldState);
  587.     }
  588.     
  589.     GetCTitle((*messH)->sendButton,sbName);
  590.     GetRString(shdName,PrefIsSet(PREF_AUTO_SEND)?SEND_BUTTON:QUEUE_BUTTON);
  591.     if (!EqualString(sbName,shdName,False,True))
  592.         SetCTitle((*messH)->sendButton,shdName);
  593.  
  594.     /*
  595.      * draw priority
  596.      */
  597.     if (GetPriorityRect(win,&r)) DrawPriority(&r,SumOf(messH)->priority);
  598. }
  599.  
  600. /************************************************************************
  601.  * PlotFlag - plot a sicn and associated flag
  602.  ************************************************************************/
  603. void PlotFlag(Rect *r,unsigned long flags,unsigned long which)
  604. {
  605.     Handle theSICN;
  606.     Rect r2;
  607.     
  608.     if (flags&which)
  609.     {
  610.         MoveTo(r->left,r->bottom-6);
  611.         DrawChar(checkMark);
  612.     }
  613.     
  614.     if (theSICN=GetResource('SICN',ICON_BAR_BASE_SICN+which))
  615.     {
  616.         SetRect(&r2,r->left+16,r->bottom-20,r->left+32,r->bottom-4);
  617.         PlotSICN(&r2,theSICN,0);
  618.     }
  619. }
  620.  
  621. /**********************************************************************
  622.  * CompKey - react to a keystroke in a composition window
  623.  **********************************************************************/
  624. void CompKey(MyWindowPtr win, EventRecord *event)
  625. {
  626.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  627.     TOCType **tocH = (*messH)->tocH;
  628.     long uLetter = UnadornMessage(event)&charCodeMask;
  629.  
  630.     if (!(event->modifiers & cmdKey) &&
  631.         (!win->txe || (event->message & charCodeMask) == TABKEY))
  632.     {
  633.         if (!win->ro && win->txe==(*messH)->txes[HEAD_LIMIT-1] &&
  634.                 !(event->modifiers&shiftKey)
  635.                 && ((*tocH)->sums[(*messH)->sumNum].flags&FLAG_TABS))
  636.             TEFakeTab(win,GetRLong(TAB_DISTANCE));
  637.         else
  638.             CompSwitchFields(messH,!(event->modifiers & shiftKey));
  639.     }
  640.     else
  641.     {
  642.         if (leftArrowChar<=uLetter && uLetter<=downArrowChar &&
  643.                 (event->modifiers&cmdKey)!=0)
  644.         {
  645.             if (PrefIsSet(PREF_NO_CMD_ARROW))
  646.                 TESomething(win,TEKEY,(short)(event->message & 0xff),event->modifiers);
  647.             else
  648.                 NextMess(tocH,messH,uLetter,event->modifiers);
  649.             return;
  650.         }
  651.         else if (event->modifiers&cmdKey)
  652.         {
  653.             if ('1'<=uLetter && uLetter<='5')
  654.                 SetPriority(tocH,(*messH)->sumNum,Display2Prior(uLetter-'0'));
  655.             else
  656.                 SysBeep(20L);
  657.             return;
  658.         }
  659.         else
  660.         {
  661.             if (win->ro && DirtyKey(event->message))
  662.             {
  663.                 if ((event->message & charCodeMask)==backSpace &&
  664.                         FindCompTx(messH,win->txe)==ATTACH_HEAD-1 &&
  665.                         SumOf(messH)->state!=SENT)
  666.                 {
  667.                     TESomething(win,TECLEAR,0,event->modifiers);
  668.                 }
  669.                 else
  670.                     AlertStr(READ_ONLY_ALRT, Stop, nil);
  671.             }
  672.             else if ((*win->txe)->teLength+1 >= INFINITY)
  673.                 WarnUser(TE_TOO_MUCH,(*win->txe)->teLength+1-INFINITY);
  674.             else
  675.             {
  676.                 TESomething(win,TEKEY,(short)(event->message & 0xff),event->modifiers);
  677.                 win->isDirty = win->isDirty || DirtyKey(event->message);
  678.             }
  679.         }
  680.     }
  681. }
  682.  
  683. /************************************************************************
  684.  * ScrollSlice - scroll a slice of a window
  685.  * with a zero offset, just invalidates
  686.  ************************************************************************/
  687. void ScrollSlice(MyWindowPtr win, short top, short bottom, short offset)
  688. {
  689.     Rect scroll;
  690.     RgnHandle rgn=NewRgn();
  691.     
  692.     top = MAX(top,win->contR.top);
  693.     SetRect(&scroll,win->contR.left,top,win->contR.right,bottom);
  694.     if (offset && rgn)
  695.     {
  696.         ScrollRect(&scroll,0,offset,rgn);
  697.         if (offset>0)
  698.             scroll.bottom = scroll.top + offset;
  699.         else
  700.             scroll.top = MAX(scroll.bottom + offset,win->contR.top);
  701.     }
  702.     InvalRect(&scroll);
  703.     DisposeRgn(rgn);
  704. }
  705.  
  706. /************************************************************************
  707.  * CompSwitchFields - switch fields in a composition window
  708.  ************************************************************************/
  709. void CompSwitchFields(MessType **messH, Boolean forward)
  710. {
  711.     MyWindowPtr win = (*messH)->win;
  712.     short newtx;
  713.     
  714.     newtx = FindCompTx(messH,win->txe);
  715.     newtx = win->txe ?
  716.             (forward ? (newtx+1)%HEAD_LIMIT : (newtx-1+HEAD_LIMIT)%HEAD_LIMIT)
  717.          : (forward ? 0 : HEAD_LIMIT-1);
  718.     while (!(*messH)->win->ro && (*messH)->txRo[newtx])
  719.          newtx = forward ? (newtx+1)%HEAD_LIMIT : (newtx-1+HEAD_LIMIT)%HEAD_LIMIT;
  720.  
  721.     HFC(win);
  722.     CompActivateField(messH,newtx); 
  723. }
  724.  
  725. /************************************************************************
  726.  * CompActivateField - make a particular field in a comp window active
  727.  ************************************************************************/
  728. void CompActivateField(MessType **messH, short newtx)
  729. {
  730.     MyWindowPtr win = (*messH)->win;
  731.     if (win->txe)
  732.         TEDeactivate(win->txe);
  733.     win->txe = (*messH)->txes[newtx];
  734.     win->ro = (*messH)->txRo[newtx];
  735.     TEActivate(win->txe);
  736.     TESetSelect(0,INFINITY,win->txe);
  737.     win->hasSelection = (*win->txe)->selEnd != (*win->txe)->selStart;
  738.     ShowInsertion(win,InsertAny);
  739.     EnableMenus(FrontWindow());
  740. }
  741.  
  742. /************************************************************************
  743.  * CompAttach - attach a document to a message
  744.  ************************************************************************/
  745. void CompAttach(MyWindowPtr win)
  746. {
  747.     Str255 text;
  748.     Str63 name;
  749.     Str63 scratch;
  750.     short vRefN;
  751.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  752.     long dirId;
  753.     
  754.     if (MySFGetFile(nil,&dirId,&vRefN,&name,-1,nil))
  755.     {
  756.         ComposeRString(text,ATTACH_FMT,GetMyVolName(vRefN,scratch),dirId,name);
  757.         if ((*(*messH)->txes[ATTACH_HEAD-1])->teLength)
  758.             AppendMessText(messH,ATTACH_HEAD-1," ",1);
  759.         AppendMessText(messH,ATTACH_HEAD-1,text+1,*text);
  760.         AttachSelect((*messH)->txes[ATTACH_HEAD-1]);
  761.         win->isDirty = True;
  762.     }
  763. }
  764.  
  765. /**********************************************************************
  766.  * CompUnattach - remove an attachment
  767.  **********************************************************************/
  768. void CompUnattach(MyWindowPtr win)
  769. {
  770.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  771.     TEHandle teh = win->txe;
  772.  
  773.     win->txe = (*messH)->txes[ATTACH_HEAD-1];
  774.     
  775.     TESomething(win,TECLEAR, 0, 0);
  776.     AttachSelect(win->txe);
  777.     win->isDirty = True;
  778.     win->txe = teh;
  779. }
  780.  
  781. /************************************************************************
  782.  * AttachSelect - broaden the current selection to include the entire
  783.  * text of an attachment
  784.  ************************************************************************/
  785. void AttachSelect(TEHandle teh)
  786. {
  787.     short selStart = (*teh)->selStart;
  788.     short selEnd = (*teh)->selEnd;
  789.     int found=0;
  790.     short anchorSpot = 0;
  791.     short colonCount=0;
  792.     short i,end;
  793.     UPtr text;
  794.  
  795.     end = (*teh)->teLength;
  796.     text = *(*teh)->hText;
  797.     for (i=0;i<end;i++)
  798.     {
  799.         if (!found && i>=selStart) found = 1;
  800.         if (i && i>=selEnd && found==1) found++;
  801.         if (text[i]==':')
  802.         {
  803.             colonCount++;
  804.             if (colonCount>4) colonCount=1;
  805.             if (colonCount==1)
  806.             {
  807.                 if (!found) anchorSpot=i;
  808.                 if (found==2)
  809.                 {
  810.                     TESetSelect(anchorSpot,i,teh);
  811.                     return;
  812.                 }
  813.             }
  814.         }
  815.     }
  816.     TESetSelect(anchorSpot,INFINITY,teh);                     
  817. }
  818.  
  819. /************************************************************************
  820.  * CompButton - handle the clicking of a button in the comp window
  821.  ************************************************************************/
  822. void CompButton(MyWindowPtr win,ControlHandle buttonHandle,long modifiers,short part)
  823. {
  824.     MessHandle messH=Win2MessH(win);
  825.     if (buttonHandle==(*messH)->sendButton)
  826.         {if (part==inButton) CompMenu(win,MESSAGE_MENU,MESSAGE_QUEUE_ITEM,modifiers);}
  827. }
  828.  
  829. /************************************************************************
  830.  * CompTxChanged - react when a teRec in a comp window has changed.
  831.  ************************************************************************/
  832. void CompTxChanged(MyWindowPtr win, int oldNl, int newNl, Boolean scroll)
  833. {
  834.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  835.     short tx;
  836.     short deltaV;
  837.     short oldBottom, newBottom;
  838.     TEHandle teh = WinTEH(win);
  839.     Boolean body = teh==(*messH)->txes[HEAD_LIMIT-1];
  840.         
  841.     win->isDirty = True;
  842.  
  843.     if (newNl != oldNl)
  844.     {
  845.         /*
  846.          * setup stuff
  847.          */
  848.         deltaV = (newNl-oldNl)*(*teh)->lineHeight;
  849.         oldBottom = (*teh)->destRect.bottom;
  850.                 
  851.         /*
  852.          * resize our field
  853.          */
  854.         (*teh)->destRect.bottom = (*teh)->destRect.top+newNl*win->vPitch;
  855.         (*teh)->viewRect.bottom = MIN((*teh)->destRect.bottom,win->contR.bottom);
  856.         newBottom = (*teh)->destRect.bottom;
  857.         if (body)
  858.         {
  859.             newBottom += (win->contR.bottom-win->contR.top)/2;
  860.             (*teh)->viewRect.bottom = win->contR.bottom;
  861.         }
  862.             
  863.         /*
  864.          * those fields after this one may need to be moved
  865.          */
  866.         for (tx=FindCompTx(messH,teh)+1;tx<HEAD_LIMIT;tx++)
  867.             OffsetTE(win,(*messH)->txes[tx],deltaV);
  868.         
  869.         CompFixDisplay(win,oldBottom,newBottom,body);
  870.     }
  871.  
  872.     if (scroll) {UpdateMyWindow(win);ShowInsertion(win,InsertAny);}
  873.     
  874.     /*
  875.      * now, see if the bar needs to be adjusted
  876.      */
  877.     CompAdjBar(win);
  878.     
  879.     /*
  880.      * details, details
  881.      */
  882.     win->hasSelection = (*teh)->selEnd != (*teh)->selStart;
  883. }
  884.  
  885. /************************************************************************
  886.  * CompFixDisplay - fix the display of a comp window after CompTxChanged
  887.  ************************************************************************/
  888. void CompFixDisplay(MyWindowPtr win,short oldBottom,short newBottom,Boolean body)
  889. {
  890.     short movement = newBottom - oldBottom;
  891.     
  892.     if (movement > 0)
  893.     {
  894.         /*
  895.          * inserted text
  896.          */
  897.         /*
  898.          * invalidate the new area; TE may not be thinking like we are
  899.          * This is not necessary if we're the body
  900.          */
  901.         if (!body) ScrollSlice(win,oldBottom,newBottom,0);
  902.         
  903.         /*
  904.          * scroll everything below the new bottom down, and invalidate newly
  905.          * emptied section.
  906.          */
  907.         ScrollSlice(win,newBottom,win->contR.bottom,movement);
  908.     }
  909.     else
  910.     {
  911.         /*
  912.          * deleted text
  913.          */
  914.         /*
  915.          * below the deleted area
  916.          */
  917.         ScrollSlice(win,newBottom,win->contR.bottom,movement);
  918.     }
  919. }
  920.  
  921. /************************************************************************
  922.  *
  923.  ************************************************************************/
  924. void CompAdjBar(MyWindowPtr win)
  925. {
  926.     MessHandle messH = (MessHandle)win->qWindow.refCon;
  927.     short top = (*(*messH)->txes[0])->destRect.top;
  928.     short contSize = win->contR.bottom-win->contR.top;
  929.     short bottom = top+CountCompLines(messH)*win->vPitch + contSize/2;
  930.     short barSize = (*win->vBar)->contrlMax*win->vPitch+contSize;
  931.     
  932.     if (barSize > bottom - top)
  933.     {
  934.         /*
  935.          * the scroll bar thinks the window is bigger than it is
  936.          */
  937.         if (GetCtlMax(win->vBar)>GetCtlValue(win->vBar))
  938.         {
  939.             /*
  940.              * the bar thinks we can scroll down; wrong
  941.              */
  942.             bottom = MAX(bottom,win->contR.bottom);
  943.             SetCtlMax(win->vBar,(bottom-top-contSize)/win->vPitch);
  944.         }
  945.     }
  946.     else if (barSize < bottom - top)
  947.         /*
  948.          * the scroll bar is too small
  949.          */
  950.         SetCtlMax(win->vBar,(bottom-top-contSize)/win->vPitch);
  951. }
  952.  
  953. Boolean ModifyQueue(short *state,uLong *when)
  954. {
  955.     DialogPtr md;
  956.     short dItem,item;
  957.     Boolean done;
  958.     Str63 timeStr,dateStr;
  959.     uLong secs = *when ? *when+ZoneSecs() : LocalDateTime();
  960.  
  961.     if ((md=GetNewMyDialog(MODQ_DLOG,nil,InFront,ThirdCenterDialog))==nil)
  962.     {
  963.         WarnUser(MEM_ERR,MemError());
  964.         return(False);
  965.     }
  966.  
  967.     IUTimeString(secs,False,timeStr);
  968.     IUDateString(secs,shortDate,dateStr);
  969.     SetDIText(md,MQDL_TIME,timeStr);
  970.     SetDIText(md,MQDL_DATE,dateStr);
  971.     SelIText(md,MQDL_TIME,0,INFINITY);
  972.  
  973.     ((MyWindowPtr)md)->update = DlgUpdate;
  974.     
  975.     if (*when)
  976.       SetDItemState(md,MQDL_LATER,True);
  977.     else if (PrefIsSet(PREF_AUTO_SEND))
  978.       SetDItemState(md,MQDL_QUEUE,True);
  979.     else
  980.         SetDItemState(md,MQDL_NOW,True);
  981.  
  982.     /*
  983.      * now, display the dialog
  984.      */
  985.     ShowWindow(md);
  986.     HiliteButtonOne(md);
  987.     PushCursor(arrowCursor);
  988.     do
  989.     {
  990.         done=False;
  991.         ModalDialog(DlgFilter,&dItem);
  992.         switch (dItem)
  993.         {
  994.             case MQDL_LATER:
  995.                 SelIText(md,MQDL_TIME,0,INFINITY);
  996.                 /* fall-through */
  997.             case MQDL_TIME:
  998.             case MQDL_DATE:
  999.               dItem = MQDL_LATER;
  1000.                 /* fall-through */
  1001.             default:
  1002.                 for (item=MQDL_NOW;item<=MQDL_UNQUEUE;item++)
  1003.                   if (GetDItemState(md,item)!=(item==dItem))
  1004.                       SetDItemState(md,item,item==dItem);
  1005.                 break;
  1006.             case MQDL_OK:
  1007.             case MQDL_CANCEL:
  1008.             case CANCEL_ITEM:
  1009.                 done = True;
  1010.                 break;
  1011.         }
  1012.         if (done && dItem==MQDL_OK && GetDItemState(md,MQDL_LATER))
  1013.         {
  1014.             GetDIText(md,MQDL_DATE,dateStr);
  1015.             GetDIText(md,MQDL_TIME,timeStr);
  1016.             if (!(*when=QueueDate2Secs(timeStr,dateStr))) done=False;
  1017.         }
  1018.     }
  1019.     while(!done);
  1020.     PopCursor();
  1021.     
  1022.     if (done = (dItem!=MQDL_CANCEL && dItem!=CANCEL_ITEM))
  1023.     {
  1024.       if (GetDItemState(md,MQDL_UNQUEUE))
  1025.           *state = SENDABLE;
  1026.         else
  1027.           *state = GetDItemState(md,MQDL_NOW) ? SENT : QUEUED;
  1028.         if (!GetDItemState(md,MQDL_LATER)) *when = 0;
  1029.     }
  1030.     DisposDialog(md);
  1031.  
  1032.   if (done) SetSendQueue();
  1033.     return(done);
  1034. }
  1035.  
  1036. uLong QueueDate2Secs(UPtr timeStr,UPtr dateStr)
  1037. {
  1038.   uLong when;
  1039.     uLong now = LocalDateTime();
  1040.   long lenUsed;
  1041.     LongDateRec dateLDR,timeLDR;
  1042.     DateCacheRecord dc;
  1043.     DateTimeRec dtr;
  1044.     uShort dateRet=fatalDateTime;
  1045.     short timeRet;
  1046.     
  1047.     InitDateCache(&dc);
  1048.     WriteZero(&dateLDR,sizeof(dateLDR));
  1049.     WriteZero(&timeLDR,sizeof(timeLDR));
  1050.     timeRet = String2Time(timeStr+1,*timeStr,&dc,&lenUsed,&timeLDR);
  1051.     dateRet = String2Date(dateStr+1,*dateStr,&dc,&lenUsed,&dateLDR);
  1052.     if (dateRet > fatalDateTime && timeRet > fatalDateTime)
  1053.     {
  1054.       WarnUser(DATE_ERROR,0);
  1055.         return(0);
  1056.     }
  1057.     Secs2Date(LocalDateTime(),&dtr);
  1058.     if (timeRet < fatalDateTime)
  1059.     {
  1060.       dtr.hour = timeLDR.od.oldDate.hour;
  1061.         dtr.minute = timeLDR.od.oldDate.minute;
  1062.         dtr.second = timeLDR.od.oldDate.second;
  1063.     }
  1064.     if (dateRet < fatalDateTime)
  1065.     {
  1066.       dtr.year = dateLDR.od.oldDate.year;
  1067.         dtr.month = dateLDR.od.oldDate.month;
  1068.         dtr.day = dateLDR.od.oldDate.day;
  1069.         dtr.dayOfWeek = dateLDR.od.oldDate.dayOfWeek;
  1070.     }
  1071.     Date2Secs(&dtr,&when);
  1072.     if (when < now && dateRet >= fatalDateTime && when + 24*3600 > now) when += 24*3600;
  1073.     if (when < now) {WarnUser(THE_PAST,0); return(0);}
  1074.     return(when-ZoneSecs());
  1075. }
  1076.  
  1077. void WarpQueue(uLong secs)
  1078. {
  1079.   TOCHandle tocH = GetOutTOC();
  1080.     MSumPtr sum;
  1081.   uLong now = GMTDateTime();
  1082.     
  1083.     if (tocH)
  1084.     {
  1085.       for (sum=(*tocH)->sums;sum<(*tocH)->sums+(*tocH)->count;sum++)
  1086.           if (sum->state == QUEUED && sum->seconds)
  1087.             {
  1088.               if (!secs) sum->seconds = 0;
  1089.                 else if (sum->seconds-now < secs) sum->seconds = now;
  1090.             }
  1091.         SetSendQueue();
  1092.     }
  1093. }
  1094.  
  1095. /************************************************************************
  1096.  * CompHasChanged - called after a text change
  1097.  ************************************************************************/
  1098. void CompHasChanged(MyWindowPtr win,TEHandle teh,short oldNl,short newNl)
  1099. {
  1100.     CompTxeTo(win,teh);
  1101.     CompTxChanged(win,oldNl,newNl,False);
  1102. }
  1103.  
  1104. /************************************************************************
  1105.  * CompIconRect - get the rect for a particular icon in the icon bar
  1106.  ************************************************************************/
  1107. Rect *CompIconRect(Rect *r,MessHandle messH,short index)
  1108. {
  1109.     short h1,h2,width,advance;
  1110.     Rect tr;
  1111.     
  1112.     /*
  1113.      * the left and right margins of the icon area
  1114.      */
  1115.     GetPriorityRect((*messH)->win,&tr);
  1116.     h1 = tr.right-tr.left + I_WIDTH;
  1117.     tr = (*(*messH)->sendButton)->contrlRect;
  1118.     h2 = tr.right-tr.left + I_WIDTH;
  1119.     
  1120.     /*
  1121.      * how wide is the whole thing?
  1122.      */
  1123.     tr = ((GrafPtr)(*messH)->win)->portRect;
  1124.     width = tr.right-tr.left-h1-h2;
  1125.  
  1126.     /*
  1127.      * now, calc the advance width
  1128.      */
  1129.     advance = (width - ICON_BAR_NUM*I_WIDTH)/(ICON_BAR_NUM-1)+I_WIDTH;
  1130.     
  1131.     /*
  1132.      * ok, now we can make an answer
  1133.      */
  1134.     SetRect(r,h1+index*advance,1,h1+index*advance+I_WIDTH,(*messH)->win->topMargin-4);
  1135.   return(r);
  1136. }